﻿Imports System.Reflection
Imports System.Linq.Expressions

Namespace Load

    ''' <summary>
    ''' フェッチクエリー
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <remarks></remarks>
    Public Class FetchQuery(Of T)
        Implements IQueryable(Of T)
        Implements IQueryable
        Implements IOrderedQueryable(Of T)
        Implements IOrderedQueryable
        Implements IQuery
        Implements IQuery(Of T)

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <param name="provider">クエリプロバイダー</param>
        ''' <param name="fetchTarget">フェッチ対象となるリスト</param>
        ''' <remarks></remarks>
        Public Sub New(provider As QueryProviderBase, fetchTarget As ICollection(Of T))
#If DEBUG Then
            If provider Is Nothing Then Throw New ArgumentNullException("provider")
#End If
            _provider = provider
            Me.Expression = Expression.Constant(Me)
            Me.FetchTarget = fetchTarget
        End Sub

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <param name="provider">クエリプロバイダー</param>
        ''' <param name="expression">式ツリー</param>
        ''' <param name="fetchTarget">フェッチ対象となるリスト</param>
        ''' <remarks></remarks>
        Public Sub New(provider As QueryProviderBase, expression As Expression, fetchTarget As ICollection(Of T))
#If DEBUG Then
            If provider Is Nothing Then Throw New ArgumentNullException("provider")
            If expression Is Nothing Then Throw New ArgumentNullException("expression")
            If Not GetType(IQueryable(Of T)).IsAssignableFrom(expression.Type) Then Throw New ArgumentOutOfRangeException("expression")
#End If
            _provider = provider
            Me.Expression = expression
            Me.FetchTarget = fetchTarget
        End Sub

        ''' <summary>
        ''' フェッチ対象となるリスト
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Property FetchTarget As ICollection(Of T)

        Private _provider As QueryProviderBase
        ''' <summary>
        ''' クエリープロバイダー
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Provider() As QueryProviderBase
            Get
                Return _provider
            End Get
            Friend Set(value As QueryProviderBase)
                _provider = value
            End Set
        End Property

        ''' <summary>
        ''' 式ツリー
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property Expression As Expression Implements IQuery.Expression

#Region "IQuery"
        Friend Property Builders As New List(Of Action(Of Func(Of MemberInfo, String), System.Func(Of Object, String), System.Action(Of String))) Implements IQuery.ParameterBuilders

        Public Sub BuildParameter(nameReader As System.Func(Of System.Reflection.MemberInfo, String), prmRegister As System.Func(Of Object, String), whereRegister As System.Action(Of String)) Implements IQuery.BuildParameter
            For Each item In Me.Builders
                item.Invoke(nameReader, prmRegister, whereRegister)
            Next
        End Sub

        Public Property Provider1 As QueryProviderBase Implements IQuery.Provider
            Get
                Return Me.Provider
            End Get
            Friend Set(value As QueryProviderBase)
                Me.Provider = value
            End Set
        End Property
#End Region

#Region "IQueryable"
        Public ReadOnly Property ElementType As System.Type Implements System.Linq.IQueryable.ElementType
            Get
                Return GetType(T)
            End Get
        End Property

        Public ReadOnly Property IQueryable_Expression As System.Linq.Expressions.Expression Implements System.Linq.IQueryable.Expression
            Get
                Return Me.Expression
            End Get
        End Property

        Public ReadOnly Property IQueryable_Provider As System.Linq.IQueryProvider Implements System.Linq.IQueryable.Provider
            Get
                Return Me.Provider
            End Get
        End Property
#End Region

#Region "IEnumerable"
        Private Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
            'フェッチ対象となるリストにクエリ結果を充填
            For Each item In DirectCast(Me.Provider.Execute(Me.Expression), IEnumerable(Of T)).AsEnumerable
                FetchTarget.Add(item)
            Next
            Return FetchTarget.GetEnumerator
        End Function

        Private Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return Me.GetEnumerator1
        End Function
#End Region

#Region "ICloneableExporter"
        Public Function Clone() As ICloneableExporter(Of T) Implements ICloneableExporter(Of T).Clone
            Return CloneableExporter.Clone(Me.ToList)
        End Function

        Private Function ToArray1() As T() Implements ICloneableExporter(Of T).ToArray
            Return Me.ToArray
        End Function

        Public Function ToItem() As T Implements ICloneableExporter(Of T).ToItem
            Dim lst = Me.ToList
            If lst.Count <> 1 Then Return Nothing
            Return lst.First
        End Function

        Private Function ToList1() As System.Collections.Generic.List(Of T) Implements ICloneableExporter(Of T).ToList
            Return Me.ToList
        End Function
#End Region

    End Class

End Namespace
